/*
   Copyright (c) 2019 LinkedIn Corp.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package com.linkedin.restli.tools.symbol;

import com.linkedin.data.codec.symbol.SymbolTableMetadata;
import com.linkedin.data.codec.symbol.SymbolTableMetadataExtractor;
import java.util.List;


/**
 * Handle symbol table name generation and extraction of information.
 *
 * <p>These are meant ONLY for use by the {@link RestLiSymbolTableProvider} that prefixes server node uri and a prefix to
 * the symbol table name to implement a symmetric symbol table exchange protocol between Rest.li services. Symbol table
 * names generated by this class are encoded in the form of ServerNodeUri|SymbolTablePrefix-SymbolsHashCode</p>
 */
class SymbolTableNameHandler extends SymbolTableMetadataExtractor
{
  private static String PREFIX_HASH_SEPARATOR = "-";

  private final String _symbolTablePrefix;
  private final String _serverNodeUri;

  /**
   * Constructor
   *
   * @param symbolTablePrefix  The prefix to use for symbol tables vended by this instance.
   * @param serverNodeUri      The URI on which the current service is running.
   */
  SymbolTableNameHandler(String symbolTablePrefix, String serverNodeUri)
  {
    _symbolTablePrefix = symbolTablePrefix;
    _serverNodeUri = serverNodeUri;
  }

  /**
   * Generate the symbol table name.
   *
   * @param symbols           The list of symbols.
   *
   * @return The generated symbol table name in the form of ServerNodeUri|SymbolTablePrefix-SymbolsHashCode
   */
  String generateName(List<String> symbols)
  {
    if (_serverNodeUri == null)
    {
      throw new IllegalStateException("Cannot generate symbol table name with null server node URI.");
    }

    return _serverNodeUri + SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR + _symbolTablePrefix
        + PREFIX_HASH_SEPARATOR + symbols.hashCode();
  }

  @Override
  protected SymbolTableMetadata createMetadata(String serverNodeUri, String tableName) {
    // A table is remote if the server node URI does not match the current server node URI.
    boolean isRemote = _serverNodeUri == null || !_serverNodeUri.equals(serverNodeUri);
    return new SymbolTableMetadata(serverNodeUri, tableName, isRemote);
  }

  /**
   * Rename the original table name, replacing the existing url prefix with this instance's url prefix if it exists. If
   * this instance doesn't have a url prefix, then this method is a no-op and returns the table name as is.
   *
   * @param existingTableName The existing table name.
   *
   * @return The new name with the url prefix in the existing name replaced with this instance's url prefix.
   */
  String replaceServerNodeUri(String existingTableName)
  {
    if (_serverNodeUri == null)
    {
      return existingTableName;
    }

    int index = existingTableName.indexOf(SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR);

    if (index == -1 || index == 0 || index == existingTableName.length() - 1)
    {
      throw new RuntimeException("Unexpected name format for name: " + existingTableName);
    }

    return _serverNodeUri + SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR + existingTableName.substring(index + 1);
  }
}
